home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
science
/
normix21.zip
/
NORMIX21
/
PCNORMIX.FOR
< prev
next >
Wrap
Text File
|
1995-01-11
|
75KB
|
2,393 lines
c PC-NORMIX Version 2.1 (January 1995)
c Copyright (c) 1995 by John H. Wolfe. All rights reserved.
c This is a revision of Version 1.1 of PCNORMIX for the
c 286 and above. It runs on 386 and 486 pcs, compiled with Microsoft
c Fortran Power-Station, unix machines with the f77 compiler,
c and the IBM-4381 mainframe with the FORTVS compiler.
c Only the I/O differs from the 1978 IBM Mainframe version. The
c computational algorithms remain unchanged. This version of the program
c is copyrighted, unlike Version 1.1, which is in the public domain.
c It may be freely redistributed in its entirety provided that this
c copyright notice is not removed. It may not be sold for profit or
c incorporated in commercial programs without the written permission
c of the copyright holder. Permission is expressly granted for this
c program to be made available for file transfer from installations
c offering unrestricted anonymous file transfer on the Internet.
c This program is provided without any express or implied warranty.
c The user may modify or recompile the program for his/her own use on any
c one computer, provided that he/she becomes a Registered user. Distribution
c of modified or recompiled versions of this program is strictly forbidden
c without written permission from the copyright holder.
c
c This (main) program dimensions the arrays.
implicit real*8 (a-h,o-z)
real*8 likly
character*60 fmt
character*40 nform,dblank
logical normap
c external normex
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
c
c*********************************************************************
c VAX-UNIX or IBM Mainframe VMS version: Remove C from Column 1
c on next two lines:
c dimension a(56000)
c data nadim/56000/
c These dimensions are currently set to fit into 571K byte RAM with
c 123K of program and 56K 8-byte words.
c End of Mainframe statement.
c*********************************************************************
c
c*********************************************************************
c The next statement works only for MS-Fortran on a PC:
c dimension a[allocatable,huge](:)
c The next statement works only for MS-Fortran PowerStation on a PC:
dimension a[allocatable](:)
c End of MS-Fortran PC statement.
c*********************************************************************
c
c
c Logical I/O unit numbers are assigned to files as follows:
c 15 Input-form statements (filename specified interactively,
c default: "thisjob")
c 11 Input data (filename specified on input-form; if blank,
c data are read from unit 15 following the format
c statement on the input-form)
c 12 Printout of the analysis (filename specified on input-form,
c default: "prinout")
c 3 "kc3temp" Scratch unit containing factor scores
c 9 "kv9temp" Scratch unit containing raw data
c 4 "discrim" = the discriminant scores
c 7 "dumpout" the parameter estimates if iteration limit is
c reached. These can be used to continue the
c analysis by including them as initial estimates
c on a new input-form.
write(*,10)
10 format(' Enter the file name for the input-form statements (defaul
1t = "thisjob")')
read(*,'(a40)',end=20,err=20)nform
nform = dblank(nform)
if(nform .eq. ' ')nform='thisjob'
go to 30
20 nform = 'thisjob'
30 open( 15,file=nform)
write(*,*)' '
write(*,*)' Reading input form control statements from'
write(*,*)' ',nform
call inform
c
c calculate number of bytes occupied by each array
nb=max0(maxav*4,nvbles*8,168)
nb=((nb+7)/8)*8
nc=maxtyp*8
c
nx=nvbles*nsampl*4
nx=max0(nx,24000,maxav*(maxav+1)*2 )
nx=((nx+7)/8)*8
c
nvc=nvbles*nc
nv=nvbles*8
np=max0(nsemi*8,nparam*nc)
if(normap) then
ncov=nsemi*24
nvt=nvbles*nv
nr=nv
nvv=nvc
else
ncov=nsemi*nc
nvt=8
nr=8
nvv=nv
endif
kor=2*(nc+nvc+nvt)+ncov+np+nvv+nvbles*nv+(12+nvbles)*nb+ 24
1 +nsampl*4 + nsampl*24
kore=kor + nx + 123000
kor=kor/8 + 1
korx = nx/8 + 1
kor = kor + korx
c*********************************************************************
c The following two statements work only with MS Fortran on a PC.
c Remove them for the mainframe or unix versions.
nadim = kor
allocate (a(kor))
c End of MS-Fortran PC statements.
c*********************************************************************
write(*,200) kore,kor,nadim
200 format(' Storage requirement=',i8,' decimal bytes',/
1 ' Required: DIMENSION A( ',i6,')',/
2 ' This Program: DIMENSION A( ',i6,')')
if(kor .gt. nadim) then
write(*,*) ' This problem is too large. Execution terminated.'
stop
endif
vbles=nvbles
c estimate how long this run will take.
etime=dble(maxav)*(2.865d0*en*vbles+4.961d0*dble(maxav))
do 40 l=1,maxt
t=ntyp(l)+1
iters=min0(iterx, (10+nvbles/2)*( ntyp(l)-1)+2 )
ters=iters
if(normap) then
etime=etime+16667.d0*dmax1(0.d0,t+t-7.d0)+1.23d0*en*ters*t*
1(vbles+2.d0)+4.25d0*t*vbles**2+2.12d0*t*vbles**3+67.d0*t*en
else
etime=etime+0.62d0*ters*en*t*( vbles+2.0d0)*(vbles+1.d0)+4.25d0*t*
1vbles**2 +67.d0*en*t
endif
40 continue
etime=etime/25.0d+6
n1=1
n2=n1+nc/8
n3=n2+nvc/8
n4=n3+ncov/8
n5=n4+np/8
n6=n5+nc/8
n7=n6+nvc/8
n8=n7+nvv/8
n9=n8+nvbles**2
n10=n9+nvt/8
n11=n10+nvt/8
n12=n11+nb/8
n13=n12+nb/8
n14=n13+nb/8
n15=n14+nb/8
n16=n15+(maxav*nvbles+1)/2
n17=n16+(maxav+1)/2
n18=n17+nb/8
n19=n18+nx/8
n20 = n19 + (nsampl+1)/2
write (*,300)etime
300 format(//' Anticipated execution time (on 486/33DX) =',f8.2,
1' minutes' )
c
call normex(a,a(n2),a(n3),a(n4),a(n5),a(n6),a(n7),a(n8),a(n9)
1,a(n10),a(n11),a(n12),a(n13),a(n14),a(n15),a(n16),a(n17),a(n18)
2,a(n19),a(n20) )
c
kc = 3
close(kc,status='DELETE')
close(kv,status='DELETE')
write(*,*)' Analysis completed.'
stop
c
end
subroutine inform
c This subroutine reads the input form cards on which the user
c specifies the options controlling the program.
implicit real*8 (a-h,o-z)
real*8 likly
character*60 fmt
character*40 infile,lsting,dblank
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
kpun=7
maxt=0
read ( 15, 6) title
6 format ( 9a8)
read ( 15, 7)nvbles,nsampl,(ntyp(l),l=1,14),nor,enmin,
1 htest,maxav,mxhier,iterx,iprint,infile,lsting,fmt
7 format(t21,i2,t37,i4,t65,/t29,14(1x,i2)/t42,i1,t66,f3.0/
1 t68,f4.3/t34,i3,t65,i3/t20,i3,t42,i1/t22,a40/t20,a40/t13,a60)
incase = ialong(fmt)
ltime=600
if(htest .eq. 0.0d0) htest=0.999d0
normap=(nor.ne.1)
if(enmin.eq. 0.0d0) enmin=nvbles+1
if (iterx.eq.0) iterx=300
do 2 i=1,14
if (ntyp(i).ne.0) go to 2
do 1 j=i,14
if (ntyp(j).eq.0) go to 1
ntyp(i)=ntyp(j)
ntyp(j)=0
go to 2
1 continue
maxt=i-1
go to 3
2 continue
maxt=14
3 if (maxt.ne.0) go to 5
maxt=20
do 4 i=1,20
4 ntyp(i)=i
5 maxtyp=ntyp(maxt)+1
nsemi=nvbles*(nvbles+1)/2
nparam=(nvbles+1)*(nvbles+2)/2
if(normap) nparam=nvbles+1
en=nsampl
if(maxav.eq.0) maxav=2000
maxav=min0(maxav,nsampl)
ivalue=-1
infile = dblank(infile)
if(infile .eq. ' ') then
inp = 15
else
inp = 11
open( 11,file=infile)
endif
lsting = dblank(lsting)
if(lsting .eq. ' ') lsting = 'prinout'
call openit(12,lsting)
write(*,*)' Data will be read on unit#',inp,' from'
write(*,*)' ',infile
write(*,*)' The printout of the analysis will appear on'
write(*,*)' ',lsting
return
end
c
function ialong(fmt)
c Returns ialong = length of the first A format variable specified
c in the variable format fmt. If ialong = 0, no a-format was found.
c If ialong = -1, the length of the A format was unspecified.
character fmt*60,aind*3
i1 = index(fmt ,'a')
if(i1 .eq. 0) i1 = index(fmt,'A')
if(i1 .ne. 0) then
i2 = index(fmt(i1:i1+3),',')
leng = i2 - 2
if (leng .le. 0) then
print *, 'No length specified for A format'
ialong = -1
return
endif
aind = fmt(i1+1: i1+leng)
read(unit=aind,fmt='(i2)')ialong
else
ialong = 0
endif
return
end
c
function dblank(ch)
c Strip off leading blanks from a character string.
character*40 ch,dblank,db
character*1 one(40)
equivalence (db,one)
db = ch
len = 40
do 10 i=1,len
if(one(i) .eq. ' ') goto 10
nb = i - 1
go to 20
10 continue
20 if(nb .eq. 0) go to 50
do 30 i = 1,len-nb
30 one(i) = one(i+nb)
do 40 i = len-nb+1,len
40 one(i) = ' '
50 dblank = db
return
end
subroutine normex(lambda,mean,covin,mu,olam,omean,v,t,w,bmat,r,s
1,b,g,av,dense,member,x,kpath,case)
implicit real*8 (a-h,o-z)
real*8 lambda,mean,mu,likly,lnlike(20)
real*4 x,dense,av
character*60 fmt
character*40 fname
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension lambda(1), mean(1), covin(1),r(1), s(1), b(1),ndf(20),
1g(1), mu(1), av(1), olam(1), omean(1), dense(1), x(nvbles,nsampl)
2,v(1),t(1),w(1),bmat(1),member(1),kpath(2),chi(20),pchi(20)
logical*1 case(24,nsampl)
c
c This is the controlling program which calls the other subroutines.
c
c Notice that, as presently programmed, all data must be in core and
c stored in the array x. It would be relatively easy to reprogram to
c handle much larger problems by reading x one record at a time from
c disk each time initle, histog, moment, and assign are called. One
c should be careful about this, since x is used as a working storage
c area in kmean and prplot. Also, this method will slow the program
c by about 20 percent.
c
convrg=1.0d-4
kscrat=4
fname = 'discrim'
call openit(kscrat,fname)
rewind kscrat
call itime (itma)
c itime is a routine which returns the clock value in 100-ths of a
c second.
c ltime is the time limit in minutes.
itma=6000*ltime+itma
write(*,*)' Reading the data'
call initle (lambda,mean,covin,x,case)
write(*,*)' Entering HISTOG hierarchical clustering'
call histog(mean,av,dense,x,r,s,g,b,mu,covin,t,member,kpath,case)
call itime(itmb)
tmb=itmb/100.0
c write (12,15)tmb
do 8 l=1,maxt
ltye=l
iter=0
method=10 +nvbles
ntypes=ntyp(l)+1
write(*,*)' Start REVALU to use new initial estimates'
call revalu (lambda,mean,covin,av,dense,member,r,s)
call output (lambda,mean,covin,r,s)
oldlik=-1.0d08
call tytle
ldiv=0
call itime(itme)
do 5 iter=1,iterx
c write(*,*)' Start iteration',iter
call aitken (lambda,mean,covin,x,r,s,b,v,g,mu,olam,omean)
c write(*,*)'finish aitken'
elik=likly-oldlik
dlik=dabs(elik)
if (elik.gt.-1.0d-5) go to 1
ldiv=ldiv+1
if (ldiv.lt.9) go to 2
c If the likelihood fails 9 times to exceed the maximum likelihood
c of prior iterations, terminate job.
write (12,10)
if (dlik.gt.convrg) itmc=10
go to 7
1 oldlik=likly
ldiv=0
write (*,11) iter,ntyp(l),likly
c Test whether the convergence criterion is met.
if (dlik-convrg) 7,7,2
2 if (iprint.eq.0) go to 3
call output (lambda,mean,covin,r,s)
go to 4
3 write (12,11) iter,ntyp(l),likly
4 call itime (itmb)
itmc=itmb-itma
tmc=itmc/6000. +ltime
c Stop and dump current parameter estimates if time limit reached.
c if (itmc.lt.0) go to 5
c write (12,13) tmc
c go to 6
5 continue
go to 7
6 call dumper (lambda,mean,covin,r,s)
7 call itime(itmb)
c tme=(itmb-itme)/100.0
c tmr=tmc*60.0
c write (12,14)tme,tmr
call output (lambda,mean,covin,r,s)
if(ntypes.eq.2) go to 20
nrank=min0(ntypes-2,nvbles,8)
write(*,*)' Start ASSIGN'
call assign(lambda,mean,covin,x,r,s,b,v,g,mu,t,w,bmat,case)
if(normap) then
call mapper(x,r,s)
write(*,*)' Finish MAPPER plot of discriminant scores'
endif
rewind kv
read(kv) ((x(i,k),i=1,nvbles),k=1,nsampl)
c if (itmc.ge.0) go to 9
c Test whether likelihood is significantly greater for more types.
20 ratio=likly-prelik
prelik=likly
ntypes=ntyp(l)
lnlike(l) = likly
if (l.le.1) go to 8
ntyold=ntyp(l-1)
ndegre=(nparam-1)*(ntypes-ntyold)*2
chisq=2.0*ratio*(en-0.5-nvbles-ntypes/2.0)/en
pchisq=chisqp(chisq,ndegre)
ndf(l) = ndegre
chi(l) = chisq
pchi(l) = pchisq
call tytle
write (12,12) ntypes,ntyold,ratio,ndegre,chisq,pchisq
if ((htest .lt. 0.998d0) .and. (pchisq .gt. htest)) go to 9
8 continue
9 if(normap) end file kscrat
call tytle
write(12,16)
write(12,17) ntyp(1),lnlike(1)
if(maxt .gt. 1) then
do 90 l=2,maxt
write(12,17) ntyp(l),lnlike(l),chi(l),ndf(l),pchi(l)
90 continue
endif
return
c
c
10 format (/,5x,'Job terminated--iterations are not converging')
11 format (' Iteration',i4, 3x,'Log likelihood of',i3,' types in this
1 sample =',g20.8)
12 format (' Logarithm of likelihood ratio of',i3,' to',i3,' types=',
1 e18.8,/,' Pseudo Chi-square with',i3,' degrees of freedom=',f10.2
2,/,' "Probability" of null hypothesis=',f11.8)
c 13 format (39h Time limit exceeded. Computation time=f6.2,8h minutes)
c 14 format(//40x,'Iteration time =',f12.2,' seconds.'/40x,'Total time
c 1used =',f11.2,' seconds.')
c 15 format(//40x,'Time in hierarchical grouping =',f8.2,' seconds.')
16 format(/' Summary of Likelihood Statistics ',/
* ' Types Log Likelihood Chi-square DF "Probability"')
17 format(i5,g20.8,f12.2,i4,f14.4)
end
subroutine openit(no,fname)
character*40 fname
logical isther
inquire(file=fname,exist=isther)
if(isther) then
open(no,file=fname,status='OLD')
else
open(no,file=fname,status='NEW')
endif
return
end
subroutine openun(no,fname)
character*40 fname
logical isther
inquire(file=fname,exist=isther)
if(isther) then
open(no,file=fname,status='OLD',form='UNFORMATTED')
else
open(no,file=fname,status='NEW',form='UNFORMATTED')
endif
return
end
subroutine initle (lambda,mean,covin,x,case)
implicit real*8 (a-h,o-z)
real*8 lambda,mean,likly
real*4 x
character*60 fmt*60,acase*24
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension lambda(1),mean(nvbles,2),covin(nsemi,2),
1 x(nvbles,1)
logical*1 case(24,nsampl),lcase(24)
equivalence (acase,lcase)
ntypes=0
iter=0
likly=0.0
do 1 l=1,maxtyp
lambda(l)=0.0
do 1 i=1,nvbles
1 mean(i,l)=0.
naxtyp=maxtyp
if(normap) naxtyp=3
do 12 l=1,naxtyp
do 12 ij=1,nsemi
12 covin(ij,l)=0.0d0
3 do 4 j=1,nsampl
c Read in all the data.
if(incase .eq. 0) then
read (inp,fmt) (x(i,j),i=1,nvbles)
else
read (inp,fmt) acase,(x(i,j),i=1,nvbles)
c write(12,fmt) acase,(x(i,j),i=1,nvbles)
do 41 i=1,incase
41 case(i,j) = lcase(i)
endif
4 continue
do 5 k=1,nsampl
c Calculate the overall means and covariances for the whole sample.
ij=0
do 5 i=1,nvbles
mean(i,1)=mean(i,1)+x(i,k)
do 5 j=i,nvbles
ij=ij+1
5 covin(ij,1)=covin(ij,1)+x(i,k)*x(j,k)
ij=0
do 7 i=1,nvbles
do 6 j=i,nvbles
ij=ij+1
6 covin(ij,1)=(covin(ij,1)*en-mean(i,1)*mean(j,1))/(en*en)
7 mean(i,1)=mean(i,1)/en
return
c
c
8 format (f8.4)
9 format (10f8.4)
end
subroutine histog(mean,av,dense,x,r,s,g,b,mu,covin,t,member,kpath,
* case)
c The clusters which are formed are used later in the program for
c initial estimates of the parameters.
implicit real*8 (a-h,o-z)
real*8 mean,mu,likly
real*4 x,dense,r,s,av
character*60 fmt
character*40 fname
logical normap,kmax,grprin
integer b,g
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
logical*1 case(24,nsampl)
dimension mean(nvbles,maxtyp),x(nvbles,nsampl),av(nvbles,maxtyp),
1 dense(maxtyp),r(nvbles),g(1),mu(1),covin(nsemi,1),s(1)
2,member(1),b(1),t(nvbles,nvbles),kpath(1)
do 2 i=1,nsemi
2 mu(i)=covin(i,1)
kv=9
kc=3
fname = 'kv9temp'
call openun(kv,fname)
fname = 'kc3temp'
call openun(kc,fname)
do 50 ngrp = 1,3
c Repeat the hierarchical grouping three times.
rewind kv
rewind kc
write(*,*)' Factoring the variables'
call uplow(mu,nvbles,-1)
call eigen(mu,t,nvbles,0)
write(kv) ((x(i,k),i=1,nvbles),k=1,nsampl)
ii=0
do 4 i=1,nvbles
ii=ii+i
ra=1.0d0/dsqrt(mu(ii))
do 3 j=1,nvbles
3 t(j,i)=t(j,i)*ra
4 continue
do 21 k=1,nsampl
do 20 i=1,nvbles
r(i)=0.0
do 20 j=1,nvbles
20 r(i)=r(i)+t(j,i)*(x(j,k)-mean(j,1))
c write(kc) r
write(kc) (r(ir),ir=1,nvbles)
21 continue
write(*,*)' Ward hierarchical grouping'
maxhi = mxhier
if(mxhier .eq. 0) maxhi=30
maxhi = min0(maxav,maxhi)
grprin = ((mxhier .ne. 0) .or. (ngrp .eq. 3))
if(grprin) call tytle
call kmean(av,dense,x,s,member,b,g,kpath,maxav,maxhi,nsampl,
1 nvbles,kc,incase,case,grprin)
write(*,*)' Compute means of merged clusters'
rewind kv
read(kv) ((x(i,k),i=1,nvbles),k=1,nsampl)
do 24 l=1,maxav
do 24 i=1,nvbles
24 av(i,l)=0.0
l=0
do 28 k=1,nsampl
ki=kpath(k)
if(ki .le. 0) then
ki=-ki
l=l+1
endif
do 28 i=1,nvbles
28 av(i,l)=av(i,l)+x(i,ki)
ltypes=min0(10,maxav)
d=0.0
ij=0
do 51 i=1,nvbles
r(i)=0.0
do 51 j=i,nvbles
ij=ij+1
51 mu(ij)=covin(ij,1)+mean(i,1)*mean(j,1)
kmax=.false.
do 57 k=1,maxav
if(member(k) .ge.ltypes) go to 55
if(d.le. 0.5) go to 55
58 ij=0
do 53 i=1,nvbles
do 53 j=i,nvbles
ij=ij+1
53 mu(ij)=mu(ij)-r(i)*r(j)/(d*en)
if(kmax) go to 50
d=0.0
do 54 i=1,nvbles
54 r(i)=0.0
55 d=d+dense(k)
do 56 i=1,nvbles
56 r(i)=r(i)+av(i,k)
kmax=k.eq.maxav
if(kmax) go to 58
57 continue
50 continue
do 40 l=1,maxav
do 40 i=1,nvbles
40 av(i,l)=av(i,l)/dense(l)
c if mxhier = 0, no printout occurs of means at each stage of the
c hierarchical grouping. Elsewhere in the program, mxhier defaults
c to 30, but if you want this printout here, you must enter a
c positive integer explicitly for mxhier on the input form.
if(mxhier .eq. 0) return
call tytle
write (12,1140)
last=0
do 440 i=1,maxav
k=last+1
l=dense(i)
last=l+k-1
write (12,1130)i,l
write (12,1135)(kpath(j),j=k,last)
440 write (12,1150)(av(j,i),j=1,nvbles)
do 35 mtypes=2,maxav
ltypes=maxav-mtypes+2
last=g(ltypes)
j=last
jind=1
do 29 i=1,nvbles
29 r(i)=av(i,j)*dense(j)
awt=dense(j)
30 j=j+jind
if(j.gt.maxav) go to 32
if(member(j).lt.ltypes*jind) go to 32
do 31 i=1,nvbles
31 r(i)=r(i)+av(i,j)*dense(j)
awt=awt+dense(j)
if(member(j).ge.ltypes) go to 30
32 if(j.lt.last) go to 33
j=last
jind=-1
go to 30
33 do 34 i=1,nvbles
34 r(i)=r(i)/awt
write (12,1160)last,j
nj=awt
nj1=b(j)
nj2=nj1+nj-1
write (12,1130)j,nj
write (12,1135)(kpath(m),m=nj1,nj2)
35 write (12,1150)(r(i),i=1,nvbles)
1130 format(/30x,'Cluster',i4,10x,i4,' points')
1135 format(20i4)
1140 format(42x,'Kmeans analysis'//)
1150 format(10f12.4)
1160 format(/20x,'Merging cluster',i4,' with cluster',i4,
1' results in the revised' )
return
c
end
subroutine kmean(av,wt,a,best,member,kgrp,lgrp,kpath,n,mxhier,
1 ns,nv,nti,incase,case,grprin)
c Adapted from ward's hierarchical grouping program
c by John H. Wolfe
c
c This routine combines MacQueen's Kmeans clustering procedure with
c Ward's hierarchical grouping.
c ***references***
c MacQueen,J. Fifth Berkeley Symposium(1965)
c Ward,J. PERSUB Reference Manual(PRL-TR-67-3) (1967)
c Definitions:
c n = maximum number of groups
c ns= number of points to be grouped.
c nv= number of variables.
c nti=logical unit containing data to be clustered.
c wt(i)=number of points in cluster i.
c av(j,i)=mean of variables j in cluster i.
c a = n*(n+1)/2 words of working storage used by the program
c
c On return from this routine, kpath will be a list of points.
c kpath(i) will be negative for the first member of one of the n
c groups and kpath(i+1),kpath(i+2), etc., will have the remaining
c members in that group. member(j) will be the number of groups
c left after the j-th group is merged with another group.
c
c This routine expects that logical unit nti contains the data to
c be clustered. The data should have been properly scaled or
c converted to factor scores and written as unformatted (binary)
c records
c
logical*1 case(24,ns)
logical grprin
dimension a( 1),kgrp(n),kpath(ns),wt(n),member(n),best(n),av(nv,n)
1,lgrp(n)
c
c The program first performs a kmeans analysis and then
c hierarchically groups the groups.
c 1. Initially, each of the first n data points is a separate cluster.
c 2. The inter-group distances, a, are computed.
c 3. The nearest two groups are combined.
c 4. A new data point is read into the space left by the merger.
c 5. The distances of all the clusters to this new point are computed.
c 6. Go back to step 3 until all the data has been read.
c 7. Hierarchically group the n groups.
c
c Initialize
na = (n * (n+1))/2
ntwo=n+n
none=n-1
if(nti.ne.0) rewind nti
ks=n
numg=n
do 10 i=1,n
if(nti.ne.0) read (nti) (av(k,i),k=1,nv)
c write(*,*)i,(av(k,i),k=1,nv)
lgrp(i)=i
kgrp(i)=i+1
best(i)=1.0e35
10 wt(i)=1.0
kgrp(n)=0
do 15 i=1,ns
15 kpath(i)=0
c A group is identified by the least index of its members
c If i is a member of a group, kpath(i) is another member.
c If i is the beginning of a group, kgrp(i) begins the next group.
c lgrp(i)= the leading member of group i
c A diagonal element of a is the within-group dispersion.
c The value of a in row i,column j is the dispersion which would
c result from combining groups i and j .
c Compute di block 2
c write(*,*) 'Compute a(ij)'
ij=0
do 40 i=1,none
ij=ij+1
a(ij)=0.0
c write(*,*)i,(av(k,i),k=1,nv)
do 30 j=i,none
ij=ij+1
a(ij)=0.0
do 20 k=1,nv
20 a(ij)=a(ij)+(av(k,i)-av(k,j+1))**2
a(ij)=a(ij)/2.0
dit=a(ij)
if(dit.ge.best(i)) go to 30
best(i)=dit
member(i)=j+1
30 continue
40 continue
a(na)=0.0
50 i=1
di=1.0e35
do 60 j=1,numg
if(best(i).ge.di) go to 60
di=best(i)
ids=i
60 i=kgrp(i)
70 jds=member(ids)
if(jds.gt.ids) go to 100
ids=jds
go to 70
c Update kgrp and kpath block 3
100 i=ids
numg=numg-1
best(jds)=di
110 if(kgrp(i)-jds)120,130,120
120 i=kgrp(i)
go to 110
130 kgrp(i)=kgrp(jds)
kgrp(jds)=-numg
i=lgrp(ids)
140 if(kpath(i))150,160,150
150 i=kpath(i)
go to 140
160 kpath(i)=lgrp(jds)
c Update hyp matrix block 4
i=1
best(ids)=1.0e35
l =((ntwo-ids)*(ids-1))/2+ids
k =((ntwo-jds)*(jds-1))/2+jds
m=l+jds-ids
plop=a(m)
tsum1=a(m)*(wt(ids)+wt(jds))
tsum3= (a(l)* wt(ids))+ (a(k)*wt(jds))
a(l)=plop
do 350 im=1,numg
ii=((ntwo-i )*(i -1))/2+i
if(i-ids)210,350,240
210 m=ii+ids-i
go to 250
240 m=l+i-ids
250 if(i-jds)260,270,270
260 m1=ii+jds-i
go to 280
270 m1=k+i-jds
280 a(m)=(a(m1)*(wt(i)+wt(jds))+ (
1a(m)*(wt(i)+wt(ids)))+ (tsum1
2-tsum3-(a(ii)*wt(i))))/(wt(i)+wt(jds)+wt(ids) )
dit=a(m)-plop-a(ii)
if(dit.ge.best(ids)) go to 290
best(ids)=dit
member(ids)=i
290 if(member(i).ne.ids.and.member(i).ne.jds) go to 340
best(i)=1.0e35
j=i
300 j=kgrp(j)
if(j.le.0) go to 350
jj=((ntwo-j)*(j-1))/2+j
ij=ii+j-i
dot=a(ij)-a(ii)-a(jj)
if(dot.ge.best(i)) go to 300
best(i)=dot
member(i)=j
go to 300
340 if(dit.ge.best(i)) go to 350
best(i)=dit
member(i)=ids
350 i=kgrp(i)
wts=wt(ids)
wt(ids)=wt(ids)+wt(jds)
if(ks.eq.ns) go to 359
ks=ks+1
numg=n
lgrp(jds)=ks
kgrp(jds-1)=jds
kgrp(jds)=jds+1
kgrp(n)=0
do 351 i=1,nv
351 av(i,ids)=(wts*av(i,ids)+wt(jds)*av(i,jds))/wt(ids)
read(nti) (av(i,jds),i=1,nv)
wt(jds)=1.0
best(jds)=1.0e35
m=jds
jadd=n
jj=1
do 355 j=1,n
dit=a(jj)
if(j.eq.jds) go to 354
do 352 i=1,nv
352 dit =dit +(av(i,jds)-av(i,j))**2
a(m)=dit *wt(j )/(wt(j )+1.0)
dit=a(m)-a(jj)
if(j.gt. jds) go to 353
if(dit .ge. best(j)) go to 354
best(j)=dit
member(j)=jds
go to 354
353 if(dit .ge. best(jds)) go to 354
best(jds)=j
member(jds)=j
best(jds)=dit
354 jadd=jadd-1
if(j.ge.jds) jadd=1
jj=jj+n-j+1
355 m=m+jadd
359 if(numg-1) 360,360,50
c Out put block 5
360 la=0
do 361 i=1,n
l=lgrp(i)
if(kpath(l).eq.0) la=i
361 kpath(l)=-kpath(l)
call relist(kpath)
k=0
do 362 i=2,ns
if(kpath(i).ge.0) go to 362
k=k+1
do 363 l=1,n
if(lgrp(l).eq. kpath(i-1)) go to 364
363 continue
364 member(k)=l
kpath(i-1)=-kpath(i-1)
kpath(i)=-kpath(i)
wt(k)=0.0
362 wt(k)=wt(k)+1.0
wt(n)=wt(n)+1.0
if(la.eq.0) go to 371
kpath(ns)=-kpath(ns)
member(n)=la
wt(n)=1.0
do 370 k=1,n
l=member(k)
366 if(l-k) 367,370,368
367 l=member(l)
go to 366
368 do 369 j=1,nv
temp=av(j,k)
av(j,k)=av(j,l)
369 av(j,l)=temp
370 continue
371 do 372 l=1,n
k=member(l)
j=-kgrp(k)
member(l)=j
372 lgrp(j+1)=l
c Member(l)= stage of group l
c lgrp(j)= group whose stage is j-1
l=0
do 373 k=1,ns
if(kpath(k).gt.0) go to 373
l=l+1
kgrp(l)=k
373 continue
c kgrp(l)= the position in kpath which begins group l
if(grprin) call hgraph(mxhier,n,ns,kpath,member,incase,case)
return
end
subroutine hgraph(mxhier,n,ns,kpath,member,incase,case)
integer rank,stage
character*2 bar,gram
character char*1,alph*24,fmt8x*180,fmt9x*60
logical*1 case(24,ns),lchar
dimension kpath(ns),member(n)
dimension gram(80),bar(2)
equivalence (char,lchar)
data bar/' .',' X'/
c lineln = number of columns displayed on one page
lineln = 30
if(incase .gt. 0) then
m1 = max0(1,(incase+1)/3)
m2 = incase-m1+2
write(fmt8x,1010)m1,m2
1010 format(
*'(1h,39x,21hHierarchical Grouping,//60x,16hNumber of Groups,/,
* 3x,24hRank Item Kmeans Stage,',i2,'x,2hID,',i2,'x,i3,i8,5i10)')
c write(12,*)' fmt8x =',fmt8x
endif
do 430 lcol=1,mxhier,lineln
k2=min0(lcol+lineln-1,mxhier)
linelg = (k2+1-lcol)
linelg2 = linelg*2
if(incase .ne. 0) then
c Set up format fmt9x for one line, depending on part of printout
write(fmt9x,1020)incase,linelg
1020 format('(2i6,2i7,4x,a',i2.2,',2x,',i2,'a2)')
c write(12,*)' fmt9x =',fmt9x
endif
kmean=0
do 420 rank=1,ns
if(mod(rank,50) .eq. 1) then
if(incase .eq. 0) then
write (12,1030)lcol,(j,j=lcol+4,k2,5)
else
write(12,fmt8x)lcol,(j,j=lcol+4,k2,5)
endif
endif
1030 format(1h,39x,'Hierarchical Grouping'//60x,'Number of Groups'/3x
1,'Rank Item Kmeans Stage',5x,i10,i8,5i10)
stage=n+1
j=kpath(rank)
if(j.le.0) then
kmean=kmean+1
stage=member(kmean)
j=-j
endif
lk=max0(0,stage -lcol+1)+ 1
if(incase .gt. 0) then
c Copy case ==> alph
do 400 ii=1,incase
lchar = case(ii,j)
400 alph(ii:ii) = char
endif
do 410 k=1,linelg2
if(k .lt. lk) then
gram(k)=bar(2)
else
gram(k)=bar(1)
endif
410 continue
if(incase .eq. 0) then
write (12,1040)rank,kpath(rank),kmean,stage,
* (gram(ig),ig=1,linelg)
1040 format(2i6,2i7,14x,30a2)
else
write (12,fmt9x)rank,kpath(rank),kmean,stage,alph,
* (gram(ig),ig=1,linelg)
endif
420 continue
430 continue
return
end
subroutine relist(kpath)
c
c Given a list, kpath, such that kpath(i) is the next element of
c the list after i, this routine reorders kpath so that kpath(i) is
c the i-th element of the list.
c
dimension kpath(1)
l=1
j=0
1 j=j+1
m=iabs(l)
2 if(m-j) 3,4,5
3 m=iabs(kpath(m))
go to 2
4 i=kpath(m)
go to 6
5 i=kpath(m)
kpath(m)=kpath(j)
6 kpath(j)=l
l=i
if(i.ne.0) go to 1
return
end
subroutine revalu (lambda,mean,covin,av,dense,member,r,s)
c This subroutine re-evaluates previous estimates of the parameters
c and finds initial estimates preparatory to iteration. It is called
c every time the number of hypothesized types is increased.
c Revised 9 Jan 95 to fix a bug reported by B. Robinson in which
c only the means of the first cluster were read under the normap option.
implicit real*8 (a-h,o-z)
real*8 lambda,mean,likly
real*4 dense ,av
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension lambda(1), mean(nvbles,2), covin(nsemi,2), av(nvbles,2),
1 dense(1),member(1),r(nvbles),s(nvbles)
ltypes=ntypes-1
do 1 l=2,ntypes
lambda(l)=0.0d0
do 1 i=1,nvbles
1 mean(i,l)=0.0d0
l=1
do 2 k=1,maxav
if(member(k).lt.ltypes) l=l+1
lambda(l)=lambda(l)+dense(k)
do 2 i=1,nvbles
2 mean(i,l)=mean(i,l)+av(i,k)*dense(k)
do 4 l=2,ntypes
do 3 i=1,nvbles
3 mean(i,l)=mean(i,l)/lambda(l)
4 lambda(l)=lambda(l)/en
ij=0
do 5 i=1,nvbles
do 5 j=i,nvbles
ij=ij+1
covin(ij,2)=covin(ij,1)+mean(i,1)*mean(j,1)
do 5 l=2,ntypes
5 covin(ij,2)=covin(ij,2)-lambda(l)*mean(i,l)*mean(j,l)
if(.not. normap) then
do 6 l=2,ntypes
do 6 i=1,nsemi
6 covin(i,l)=covin(i,2)
endif
8 if((ivalue .eq. 0) .or. (ltypes .lt. ivalue)) return
if(ltypes .eq. ivalue) go to 10
read ( 15, 100)ivalue,imn,istd,icor
go to 8
10 sump = 0.0d0
do 17 l=2,ntypes
read ( 15, *)p
if(p.ne.0.0d0) lambda(l)=p
sump = sump + lambda(l)
if(imn.ne.0) read ( 15, *)(mean(i,l),i=1,nvbles)
if(normap .and. l .ne. ntypes) go to 17
if(istd.ne.0) then
read ( 15, *)(s(i),i=1,nvbles)
k=0
do 15 i=1,nvbles
if(icor.eq.0) then
do 12 j=1,nvbles
12 r(j)=0.0d0
r(i)=1.0d0
else
read ( 15, *)(r(j),j=1,nvbles)
endif
do 15 j=i,nvbles
k=k+1
15 covin(k,l)=r(j)*s(j)*s(i)
endif
17 continue
c Standardize lambdas to sum to one.
do 18 l=2,ntypes
18 lambda(l) = lambda(l)/sump
return
100 format(25x,i2,16x,i1,10x,i1,14x,i1)
end
subroutine itime(it)
it = 0
return
end
subroutine aitken (lambda,mean,covin,x,r,s,b,v,g,mu,olam,omean)
c This subroutine does all the computations of a single iteration
c for improved estimates of the parameters.
implicit real*8 (a-h,o-z)
real*8 lambda,mean,mu,likly
real*4 x
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension lambda(1),mean(nvbles,2),covin(nsemi,2),mu(nparam,2),
1 b(1),olam(1),omean(nvbles,2) ,r(1),s(1),g(1),x(1),v(nvbles,1)
xlimit=amin0(40,(iter/5)*10)
c When xlimit=0, all points are assigned a membership probability of
c 1.0 in their nearest cluster.
n=nvbles-1
luck=1
bigest=20.0
small=1.0-1.0/bigest
lqq=nsemi
do 3 l=2,ntypes
if(l.gt.2.and.normap) go to 2
call syminv (covin,nvbles,detm,r,s,g,lqq)
if(normap) go to 2
if (enmin.lt.en*lambda(l)) go to 2
lsing=l-1
nsing=en*lambda(l)
oldlik=-1.0d+10
write (12,101)lsing,nsing,oldlik
101 format(' Type',i3,' with ',i3,' points approaching singularity'/
1' Log Likelihood re-initialized to',d15.8)
ij=0
do 1 i=1,nvbles
do 1 j=i,nvbles
ij=ij+1
covin(ij,l)=covin(ij,1)+mean(i,1)*mean(j,1)
do 1 m=2,ntypes
1 covin(ij,l)=covin(ij,l)-mu(i+1,m)*mu(j+1,m)/(mu(1,m)*en)
call syminv (covin,nvbles,detm,r,s,g,lqq)
2 b(l)=dlog(lambda(l))-0.5*detm
3 lqq=lqq+nsemi
likly=0.0
do 4 l=2,ntypes
do 4 i=1,nparam
4 mu(i,l)=0.0
if(normap) go to 40
iii=nvbles
ii=1
do 6 i=1,nvbles
do 5 l=2,ntypes
5 covin(ii,l)=covin(ii,l)/2.0
ii=ii+iii
6 iii=iii-1
go to 47
40 k=1
do 42 i=1,nvbles
likly=likly-0.5*covin(k,2)*(covin(k,1)+mean(i,1)**2)*en
k=k+1
if (i.gt.n) go to 42
do 41 j=i,n
likly=likly-covin(k,2)*(covin(k,1)+mean(j+1,1)*mean(i,1))*en
41 k=k+1
42 continue
do 46 l=2,ntypes
do 45 i=1,nvbles
k=i
n=nvbles
v(i,l)=0.0d0
if (i.eq.1) go to 44
do 43 j=2,i
v(i,l)=v(i,l)+covin(k,2)*mean(j-1,l)
n=n-1
k=n+k
43 continue
44 do 45 j=i,nvbles
v(i,l)=v(i,l)+covin(k,2)*mean(j ,l)
45 k=k+1
do 46 i=1,nvbles
46 b(l)=b(l)-v(i,l)*mean(i,l)*0.5d0
c write(*,*)'Start moment'
47 call moment (mean,covin,x,r,s,b,g,mu,v)
c write(*,*)'Finish moment'
byg=1.0
if (method.gt.0) go to 8
byg=bigest
do 7 l=2,ntypes
delta=mu(1,l)/en-lambda(l)
biga=lambda(l)-olam(l)
sml=1.0-1.0/byg
if (dabs(delta).lt.sml*dabs(biga)) byg=biga/(biga-delta)
if(delta) 21,7,22
21 bound=dmax1(lambda(l)*0.5d0,1.0d0/en)
if(bound.lt.-delta*byg) byg=-bound/delta
go to 7
22 bound=dmin1((1.0d0-lambda(l))*0.5d0,(en-1.0d0)/en)
if(bound.lt.delta*byg) byg=bound/delta
7 continue
8 do 12 l=2,ntypes
if(mu(1,l).lt. 1.0d0) mu(1,l)=1.0d0
olam(l)=lambda(l)
lambda(l)=lambda(l)+byg*(mu(1,l)/en-lambda(l))
lambda(l)=dmax1(1.0d-1/en,lambda(l))
ij=0
do 9 i=1,nvbles
biga=mean(i,l)-omean(i,l)
bigc=mu(i+1,l)/mu(1,l)-mean(i,l)
big=bigest
if (dabs(bigc).lt.small*dabs(biga)) big=biga/(biga-bigc)
if (method.gt.0) big=1.0
omean(i,l)=mean(i,l)
9 mean(i,l)=mean(i,l)+big*bigc
if(normap) go to 12
kj=nvbles+1
do 10 i=1,nvbles
do 10 j=i,nvbles
ij=ij+1
kj=kj+1
10 covin(ij,l)=(mu(kj,l)-mu(i+1,l)*mean(j,l)-mu(j+1,l)*mean(i,l))/mu(
11,l)+mean(i,l)*mean(j,l)
12 continue
method=iabs(method-1)
if (likly.lt.oldlik) method=luck
if(.not.normap) return
do 11 i=1,nvbles
do 11 j=i,nvbles
ij=ij+1
covin(ij,2)=covin(ij,1)+mean(i,1)*mean(j,1)
do 11 l=2,ntypes
11 covin(ij,2)=covin(ij,2)-mu(i+1,l)*mu(j+1,l)/(mu(1,l)*en)
return
end
subroutine moment (mean,covin,x,r,s,b,g,mu,v)
implicit real*8 (a-h,o-z)
real*8 mean,mu,likly
real*4 x
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
dimension mean(1),covin(1),x(1),r(1),s(1),b(1),g(1),mu(1),v(1)
c This routine computes
c mu(1,l)= sum over all individuals of their probabilities of
c membership in type l.
c mu(i+1,l)= sum over all individuals of their x(i,k)
c times their probability of membership in type l.
c mu(ij,l) = sum over all individuals of their x(i,k)*x(j,k)
c times their probability of membership in type l.
c g(l)=probability of membership in type l,
c
c
c This subroutine contains the most deeply nested loops of the
c entire normix program. The following tricks are used
c to improve object code efficiency:
c --- The routine computes its own indexes for the
c doubly-indexed arrays instead of depending on the compiler.
c x(ik) is x(i,k)
c mean(il) is mean (i,l)
c covin(m) is covin(i,j,l)
c mu(ij) is mu(i,j,l)
do 12 k=1,nsampl
call densit(mean,covin,x,r,s,b,v,g,k)
if(normap) go to 44
ij=nparam
do 11 l=2,ntypes
pm=g(l)
ia=ij+1
ij=ia+nvbles
mu(ia)=pm+mu(ia)
do 11 i=1,nvbles
z=r(i)*pm
ia=ia+1
mu(ia)=z+mu(ia)
do 11 j=i,nvbles
ij=ij+1
11 mu(ij)=mu(ij)+z*r(j)
go to 12
44 ia=nparam
do 46 l=2,ntypes
pm=g(l)
ia=ia+1
mu(ia)=pm+mu(ia)
do 46 i=1,nvbles
ia=ia+1
46 mu(ia)=r(i)*pm+mu(ia)
12 continue
return
end
subroutine tytle
implicit real*8 (a-h,o-z)
real*8 likly
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
write (12,1)
if(normap) write (12,2)
write (12,3)title
return
c
c
1 format (1h,42x,'PC-NORMIX Version 2.1',/,25x,
*'Wolfe Normal Mixture Analysis Procedure (January 1995 Revision)')
2 format(31x,'Equal Covariance Matrices Within Groups')
3 format(//4(1x, 9a8/))
end
subroutine output (lambda,mean,covin,r,s)
implicit real*8 (a-h,o-z)
real*8 lambda,mean,likly
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension mean(nvbles,2), covin(nsemi,2), lambda(1), r(1), s(1)
call tytle
ntp=ntypes-1
ktypes=ntypes
if(normap) ktypes=2
c write (*,9) nsampl,nvbles,ntp,iter,ntp,likly
write (12,9) nsampl,nvbles,ntp,iter,ntp,likly
do 8 l=1,ktypes
if (l-1) 1,1,2
1 write (12,10)
go to 3
2 ltyp=l-1
if(normap) go to 20
write (12,11) ltyp,lambda(l)
go to 3
20 write (12,21)
3 lqq=1
do 4 i=1,nvbles
s(i)=dsqrt(covin(lqq,l))
4 lqq=lqq+nvbles-i+1
if(normap.and.l.ne.1) go to 28
write (12,12) (i,i=1,nvbles)
write (12,13)(mean(i,l),i=1,nvbles)
28 write (12,14) (i,i=1,nvbles)
write (12,13) (s(i),i=1,nvbles)
write (12,15) (i,i=1,nvbles)
do 8 i=1,nvbles
kj=i-1
ij=i
if (kj.eq.0) go to 6
do 5 j=1,kj
r(j)=covin(ij,l)/(s(i)*s(j))
5 ij=ij+nvbles-j
6 do 7 j=i,nvbles
r(j)=covin(ij,l)/(s(i)*s(j))
7 ij=ij+1
8 write (12,13) (r(j),j=1,nvbles)
if(.not. normap) return
write (12,16) (i,i=1,nvbles)
do 29 l=2,ntypes
ltyp=l-1
29 write (12,17) ltyp,lambda(l),(mean(i,l),i=1,nvbles)
return
c
c
9 format (/10x,'Sample Size =',i11,/,10x,'Number of Variables =',i3,
1/,10x,'Number of Types =',i7,//25x,'Iteration Number',i4,//3x,
2'Log Likelihood of',i3,' Types in this sample =',g20.8,/)
10 format (20x,'Characteristics of the Whole Sample',//)
11 format (/20x,'Characteristics of Type',i4,//15x,'The Proportion of
1 the Population from this Type=',f6.3/)
12 format (34x,'Means',/10(i8,9i12,/))
13 format (10f12.4)
14 format (/27x,'Standard Deviations',/10(i8,9i12,/))
15 format (/32x,'Correlations',/10(i8,9i12,/))
21 format (//20x,'Within-group Standard Deviations and Correlations')
16 format (//30x,'Means',/' Type Lambda',i6,9i10,/10(12x,i6,9i10,/))
17 format (i4,f8.4,10f10.4/10(12x,10f10.4/))
end
subroutine dumper (lambda,mean,covin,r,s)
implicit real*8 (a-h,o-z)
real*8 lambda,mean,likly
character*60 fmt
character*40 fname
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension mean(nvbles,2), covin(nsemi,2), lambda(1), r(1), s(1)
n=2
c This routine writes parameters to a file in format readable by the
c subroutine initle.
fname ='dumpout'
call openit(kpun,fname)
do 5 l=2,ntypes
if(.not. normap) n=l
ltyp=l-1
write(kpun,6) lambda(l),ltyp
write(kpun,7) (mean(i,l),i=1,nvbles)
lqq=1
do 1 i=1,nvbles
s(i)=dsqrt(covin(lqq,n))
1 lqq=lqq+nvbles-i+1
write(kpun,7) (s(i),i=1,nvbles)
do 5 i=1,nvbles
kj=i-1
ij=i
if (kj.eq.0) go to 3
do 2 j=1,kj
r(j)=covin(ij,n)/(s(i)*s(j))
2 ij=ij+nvbles-j
3 do 4 j=i,nvbles
r(j)=covin(ij,n)/(s(i)*s(j))
4 ij=ij+1
5 write(kpun,7) (r(j),j=1,nvbles)
return
c
6 format (f8.4,5x,'type',i3)
7 format (10f8.4)
end
subroutine densit (mean,covin,x,r,s,b,v,g,k)
implicit real*8 (a-h,o-z)
real*8 mean,likly
real*4 x
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension mean(1),covin(1),x(1),r(1),s(1),b(1),g(2),v(1)
if(k .gt. 1) go to 50
xlimit=40.0d0
n=nvbles-1
assign 3 to lone
if (n.eq.0) assign 6 to lone
ik=1
50 eph=0.0d0
do 1 i=1,nvbles
r(i)=x(ik)
1 ik=ik+1
il=nvbles
if(normap) go to 40
ij=nsemi
do 7 l=2,ntypes
do 2 i=1,nvbles
il=il+1
2 s(i)=r(i)-mean(il)
dsqrd= b(l)
go to lone, (3,6)
3 do 5 i=1,n
ij=ij+1
cute=s(i)*covin(ij)
do 4 j=i,n
ij=ij+1
4 cute=cute+covin(ij)*s(j+1)
5 dsqrd=dsqrd-cute*s(i)
6 ij=ij+1
7 g(l)=dsqrd-covin(ij)*s(nvbles)**2
go to 43
40 do 42 l=2,ntypes
dsqrd= b(l)
do 41 i=1,nvbles
il=il+1
41 dsqrd=dsqrd+v(il)*r(i)
42 g(l)=dsqrd
43 biga=g(2)
lot=2
bigb=biga
if (ntypes.eq.2) go to 13
do 9 l=3,ntypes
if (g(l).le.bigb) go to 9
if (g(l).le.biga) go to 8
bigb=biga
biga=g(l)
lot=l
go to 9
8 bigb=g(l)
9 continue
if ((biga-bigb).gt.xlimit) go to 13
g(lot)=1.0d0
do 10 l=2,ntypes
if (l.eq.lot) go to 10
dsqrd=g(l)-biga
g(l)=0.0d0
if (dsqrd.gt.-4d1 ) g(l)=dexp(dsqrd)
10 eph=eph+g(l)
likly=likly+dlog(eph)+biga
do 11 l=2,ntypes
11 g(l)=g(l)/eph
return
c Consider the probability of membership to be one for nearest type
13 likly=likly+biga
do 14 l=2,ntypes
14 g(l)=0.0d0
g(lot)=1.0d0
return
end
c ***********************************************************************
subroutine assign(lambda,mean,covin,x,r,s,b,v,g,mu,t,w,bmat,case)
c This routine prints the probabilities of membership of each
c individual in each type.
c It computes and prints discriminant functions and each individuals
c discriminant scores.
c Discriminant analysis. See the following references
c Cooley+Lohnes. Multivariate Proced.Behav.Sciences pages 117,189.
c Friedman and Rubin. Journ. Am. Stat. Assn. 1967, page 1167.
c
implicit real*8 (a-h,o-z)
real*8 lambda,mean,mu,likly
real*4 x
integer is(12)
character*72 fmtx1,fmtx2,fmtx3,fmtx4,fmtx5,fmtx6,fmtx7
character char*1,idstrng*3,fmt*60
character*24 alph,id(12)
logical*1 case(24,nsampl),lchar
logical normap,newhead
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
dimension covin(nsemi,1),lambda(1),g(1),r(nrank),s(1),mean(1),b(1)
1,v(1),t(nvbles,nvbles),w(nvbles,nvbles),bmat(nvbles,nvbles),
1 x(nvbles,1),mu(nparam,1)
equivalence (char,lchar)
c
c
call itime(itmda)
kc=3
rewind kc
al=likly
if(normap) then
mrank= min0(ntypes-2,nvbles)
ij=0
do 10 i=1,nvbles
do 10 j=i,nvbles
ij=ij+1
w(i,j)=covin(ij,2)
bmat(i,j)=covin(ij,1)-covin(ij,2)
10 bmat(j,i)=bmat(i,j)
c bmat is the between-group covariance matrix
c w is the within-group covariance matrix
call nroot(nvbles,bmat,w,r,t)
call tytle
write (12,3000)(l,l=1,mrank)
3000 format (//25x,'Discriminant Functions',/(16x,10i10))
do 20 i=1,nvbles
20 write (12,3010) i,(t(i,l),l=1,mrank)
3010 format (' Variable',i4,7x,10f10.4/(20x,10f10.4))
write (12,3020) (r(l),l=1,mrank)
3020 format (/' Eigenvalues of B/W=',10f10.4)
call itime(itmdb)
tmd=(itmdb-itmda)/100.0
c write (12,3030)tmd
c3030 format(//40x,'Time to Compute Discriminant Functions =',f8.2,
c 1' seconds.')
else
lqq=nsemi
do 40 l=2,ntypes
ij=0
do 30 i=1,nvbles
do 30 j=i,nvbles
ij=ij+1
30 mu(ij,l)=covin(ij,l)
call syminv (covin,nvbles,detm,r,s,g,lqq)
b(l)=dlog(lambda(l))-0.5*detm
40 lqq=lqq+nsemi
iii=nvbles
ii=1
do 60 i=1,nvbles
do 50 l=2,ntypes
50 covin(ii,l)=covin(ii,l)/2.0
ii=ii+iii
60 iii=iii-1
endif
likly=0.0d0
ntp=ntypes-1
if(incase .gt. 0) idstrng = ' ID'
if(incase .eq. 0) idstrng = ' '
m1 = (100-incase)/6
lineper = (ntp + m1 -1)/m1
m3 = 20 + incase
m4 = 5
m5 = max0(1,incase/3)
m5r = max0(1,incase - m5)
m6 = 120/(13+incase)
m7 = m5 + m5r
c Setup format fmtx1 for probability title.
write(unit=fmtx1,fmt=3040)m5+1,(incase+12)
3040 format('(8h Seq.#,',i2,'x,a3,t',i2.2,',7hCluster,8x,',
* '24hMembership Probabilities)')
c Setup format fmtx2 for discriminant score title.
if(normap) write(unit=fmtx2,fmt=3050)m5+1,(incase+12)
3050 format('(8h Seq.#,',i2,'x,a3,t',i2.2,',7hCluster,8x,',
* '19hDiscriminant Scores)')
c Setup format fmtx3 for cluster numbers at top of table.
write(unit=fmtx3,fmt=3060)(incase+19),m1
3060 format( '(t',i2.2,',',i2,'i6)' )
c Setup format fmtx4 for probabilities or discriminant scores.
if(incase .eq. 0) then
fmtx4 = '(i6,i9,4x,16f6.3,:,(/19x,16f6.3,:))'
fmtx5 = '(i6,i9,4x,16f6.2,:,(/19x,16f6.2,:))'
else
write(unit=fmtx4,fmt=3070)incase,m1,m3,m1
3070 format('(i6,3x,a',i2.2,',i7,4x,',i2,'f6.3,:, (/',i2.2,'x,',
* i2,'f6.3,:))')
write(unit=fmtx5,fmt=3080)incase,m1,m3,m1
3080 format('(i6,3x,a',i2.2,',i7,4x,',i2,'f6.2,:, (/',i2.2,'x,',
* i2,'f6.2,:))')
endif
c Set up format for printing case lists sorted by cluster.
write(fmtx6,4020)m6,m5 ,m5r
4020 format( '(',i2,'(8h Seq#,',i2,'x,a3,',i2,'x))' )
if(incase .eq. 0) then
write(fmtx7,4030)m6,m7
4030 format('(',i2,'(i8,3x,',i2,'x))')
else
write(fmtx7,4040)m6,incase
4040 format('(',i2,'(i8,3x,a',i2.2,'))')
endif
c write(12,*)' fmtx1=',fmtx1
c write(12,*)' fmtx2=',fmtx2
c write(12,*)' fmtx3=',fmtx3
c write(12,*)' fmtx4=',fmtx4
c write(12,*)' fmtx5=',fmtx5
c write(12,*)' fmtx6=',fmtx6
c write(12,*)' fmtx7=',fmtx7
c *****************************************************************
do 100 k=1,nsampl
c if line count > 44, then start a new page.
if(mod(k,45/lineper) .eq. 1) then
call tytle
write (12,fmtx1)idstrng
write (12,3090)
3090 format( 1h )
c
write (12,fmtx3) (i,i=1,ntypes-1)
write (12,3090)
endif
if(incase .gt. 0) then
c Copy case ==> alph
do 70 i=1,incase
lchar = case(i,k)
70 alph(i:i) = char
endif
c Compute the membership probabilities
call densit (mean,covin,x,r,s,b,v,g,k)
c Find the largest probability, and assign case.
xmax=0
do 80 l=2,ntypes
if (g(l).lt.xmax) go to 80
lot=l
c lot = the most probable type for individual k.
xmax=g(l)
80 continue
lit = lot -1
c If normap, then compute discriminant scores.
if(normap) then
do 90 l=1,nrank
r(l)=0.0
do 90 i=1,nvbles
90 r(l)=r(l)+t(i,l)*(x(i,k)-mean(i))
write(kc)k,lot,(r(i),i=1,nrank)
c Save discriminant scores on tape, in card-image format.
write(kscrat,4000)k,lit,(r(i),i=1,nrank)
4000 format (i6,i4,10f7.2)
else
write(kc)k,lot
endif
c Printout probabilities of membership
if(incase .eq. 0) then
write(12,fmtx4)k,lit,(g(i),i=2,ntypes)
else
write(12,fmtx4)k,alph,lit,(g(i),i=2,ntypes)
endif
100 continue
likly=al
if(normap) then
c *****************************************************************
c Print the discriminant scores
rewind kc
do 120 k=1,nsampl
c Start a new page if the line count > 44.
if(mod(k,45) .eq. 1) then
call tytle
write (12,fmtx2)idstrng
write (12,3090)
c
write (12,fmtx3) (i,i=1,nrank)
write (12,3090)
endif
if(incase .gt. 0) then
c Copy case ==> alph
do 110 i=1,incase
lchar = case(i,k)
110 alph(i:i) = char
endif
c Read the cluster and discriminant scores from unit kc.
read(kc)kk,lot,(r(i),i=1,nrank)
lit = lot -1
c Print the current case.
if(incase .eq. 0) then
write(12,fmtx5)k,lit,(r(i),i=1,nrank)
else
write(12,fmtx5)k,alph,lit,(r(i),i=1,nrank)
endif
120 continue
c If not normap, then
else
do 130 l=2,ntypes
do 130 i=1,nsemi
130 covin(i,l)=mu(i,l)
endif
c**********************************************************************
c Print case numbers and IDs for each cluster.
lap=45
do 160 lotpas=1,ntp
ik = 0
newhead = .true.
rewind kc
c Search through all the cases, looking for ones in this cluster.
do 150 k=1,nsampl
c Print new page if line count > 44.
if(lap .ge. 45) then
lap = 0
call tytle
newhead = .true.
endif
c Read cluster memberships from unit kc.
if(normap) then
read(kc)kk,lot,(r(i),i=1,nrank)
else
read(kc)kk,lot
endif
lit = lot -1
c If this case is a member of the current cluster being printed,
c store it in the row to be printed.
if(lit .eq. lotpas) then
ik = ik + 1
is(ik) = k
if(incase .gt. 0) then
c Copy case ==> alph
do 140 i=1,incase
lchar = case(i,k)
140 alph(i:i) = char
id(ik) = alph
endif
endif
c Is it time to print the row?
if((ik .eq. m6) .or. ((k .eq. nsampl) .and. (ik .gt. 0) )) then
c Print Cluster headers if new page or new cluster.
if(newhead) then
write(12,4050)lotpas
4050 format(/,30x,'Members of Cluster', i3)
write (12,3090)
write(12,fmtx6)(idstrng,i=1,m6)
write (12,3090)
newhead = .false.
lap = lap + 5
endif
if(incase .gt. 0) then
write(12,fmtx7)(is(i),id(i),i=1,ik)
else
write(12,fmtx7)(is(i),i=1,ik)
endif
ik = 0
lap = lap+1
endif
150 continue
160 continue
return
c
end
c
subroutine mapper(matrix,r,b)
implicit real*8 (a-h,o-z)
real*8 likly
character*60 fmt
logical normap
common/a/likly,xlimit,nvbles,nsampl,ntypes,nsemi,nparam,normap,kx
common/b/convrg,critrn,ratio,htest,oldlik,en,bigest,thresh,guard,
1enmin,title(36),fmt,mxhier,maxtyp,maxav,nclust,kscrat,inp,kpun,kv,
2 lot,lack,luck,iprint,ltime,maxt,iter,iterx,ltye,itmc,nrank,ivalue
3,method,incase,ntyp(20)
c The next three lines are necessary because PowerStation
c FORTRAN cannot pass real arrays to character arrays in subr. call.
logical*1 kblk,kper,kstr,lim,lookup(20),matrix(120,50),mlog
character*1 mchar,blnk,clim,str
equivalence (mlog,mchar),(kblk,blnk),(kstr,str),(lim,clim)
dimension r(nrank),b(21)
data lookup/'1','2','3','4','5','6','7','8','9','A','B','C','D',
1 'E','F','G','H','I','J','K' /,kblk/' ' /,kper/'.' /,kstr/'*' /
c This routine reads the file of discriminant scores and produces a
c semi-graphical display on the printout.
kc=3
if(nrank.le.1) return
ltypes=ntypes-1
do 10 i=1,2
i1=i+1
if(i1.gt.nrank) go to 11
do 10 j=i1,nrank
do 2 m=1,48
do 2 n=1,116
2 matrix(n,m)=kblk
do 3 m=1,48
3 matrix(1,m)=kper
do 4 n=1,116
4 matrix(n,47)=kper
rewind kc
do 5 k=1,nsampl
read(kc)l,key,(r(ir),ir=1,nrank)
m=5.0*r(i)+58.
n=-3.0*r(j)+23.
m= max0(2,min0(m,116))
n= max0(2,min0(n, 46))
lim=lookup(key-1)
mlog = matrix(m,n)
c if (matrix(m,n).ne. kblk) go to 5 [Not valid for PowerStation]
if (mchar .eq. blnk) go to 5
c if (matrix(m,n).ne. lim) lim=kstr [Not valid for PowerStation]
if (mchar .eq. clim) clim = str
5 matrix(m,n)=lim
call tytle
write (12,13) j,ltypes
ly=8
lb=1
do 8 n=1,47
lb=lb+1
go to (7,7,6), lb
6 lb=0
ly=ly-1
write (12,14) ly,(matrix(m,n),m=1,116)
go to 8
7 write (12,15) (matrix(m,n),m=1,116)
8 continue
xd=-11.0
do 9 m=1,21
xd=xd+1.0
9 b(m)=xd
10 write (12,16) (b(m),m=1,21),i
11 continue
return
c
12 format (6x,i4,10f7.2)
13 format (5x,'Discriminant Function',i2,50x,'Number of Types=',i2)
14 format (i4,116a1)
15 format (4x,116a1)
16 format (f12.0,20f5.0/45x,'Discriminant Function',i2)
end
function chisqp (chisq,ndfree)
implicit real*8 (a-h,o-z)
a=chisq*0.5
t=dexp(-a)
nn=(ndfree/2)*2
if (nn-ndfree) 2,1,2
1 p=t
t=a*t
kw=4
ak=2.0
go to 3
2 c=dsqrt(chisq)
p=2.0*area(c)
t=0.7978846*c*t
ak=1.5
kw=3
3 if (ndfree-2) 6,6,4
4 do 5 i=kw,ndfree,2
p=p+t
t=(t*a)/ak
5 ak=1.0+ak
6 chisqp=p
return
end
function area (w)
c area above w on normal curve
implicit real*8 (a-h,o-z)
x=w*.70710678118654752440
kot=2
if (x) 1,1,2
1 kot=1
x=-x
2 area=0.5/((((((.0000430638*x+.0002765672)*x+.0001520143)*x+.009270
15272)*x+.0422820123)*x+.0705230784)*x+1.0)**16
go to (3,4), kot
3 area=1.0-area
4 return
end
subroutine uplow(a,n,mode)
c changes a symmetric matrix from upper to lower triangular form
c or vice versa.
c a = an n*n symmetric matrix stored in triangular form as a
c one-dimensional array of n*(n+1)/2 elements.
c
c mode = +1 if the input has ibm storage mode 1
c mode = -1 if the input has the opposite half of ibm storage mode 1
c examples
c mode = +1 mode = -1
c a(1) a(2) a(4) a( 7) a(1) a(2) a(3) a( 4)
c a(3) a(5) a( 8) a(5) a(6) a( 7)
c a(6) a( 9) a(8) a( 9)
c a(10) a(10)
c
real*8 a,t
dimension a(1)
if(n.lt.3) go to 5
node= (mode+3)/2
nn=n*(n+1)/2
n2=n/2
nn2=nn/2
go to (1,3),node
1 k=nn+1
c reverse the order of the variables by
c interchanging a(i,j) with a(n+1-j,n+1-i)
ij=0
m=n
do 6 i=1,n2
m=m-1
k=k-i
l=k
do 2 j=i,m
ij=ij+1
t=a(ij)
a(ij)=a(l)
a(l)=t
2 l=l-j
6 ij=ij+i
go to (3,5),node
3 l=nn
c reverse a, interchanging a(i) with a(nn+1-i)
do 4 i=1,nn2
t=a(i)
a(i)=a(l)
a(l)=t
4 l=l-1
go to (5,1),node
5 return
end
function squad (s,b,mx,ls,lb)
implicit real*8 (a-h,o-z)
dimension s(1), b(1)
c this program calculates the quadratic form squad=bsb/2
c where s is a semi-matrix in upper triangular form,b is a vector,
c mx= order of matrices
c the matrices start at s(ls+1) and b(lb+1)
squad=0.0
ij=ls
n=mx+lb
if (mx-1) 5,4,1
1 nf=lb+1
na=n-1
do 3 i=nf,na
ij=ij+1
cute=b(i)*s(ij)/2.0
do 2 j=i,na
ij=ij+1
2 cute=cute+s(ij)*b(j+1)
3 squad=squad+cute*b(i)
4 squad=squad+s(ij+1)*b(n)**2/2.0
5 return
end
subroutine syminv (symtrx,norder,determ,rdumy,sdumy,untryd,lbefor)
implicit real*8 (a-h,o-z)
logical untryd
c acm algorithm 150 by h. rutishauser
c this program replaces a symmetric matrix by its inverse.
c symtrx is the symmetric matrix, stored in upper triangular form as
c a one-dimensional array starting at symtrx(lbefor+1) .
c rdumy and sdumy are temporary storage vectors used in the program.
c norder is the order of the matrix and the temporary storage areas.
c determ= natural logarithm of the determinant
dimension symtrx(1), rdumy(1), sdumy(1), untryd(1)
determ=0.0
do 1 i=1,norder
c untryd(i)=1 before i has been used as a pivot, and =0 afterwards.
1 untryd(i)=.true.
do 7 l=1,norder
c search for pivot
bigajj=0.0
n=lbefor+1
do 2 j=1,norder
t=dabs(symtrx(n))
if (.not.untryd(j).or.t.le.bigajj) go to 2
bigajj=t
k=j
nk=n
2 n=n+norder-j+1
if (bigajj.le.1.0e-50) symtrx(nk)=1.0e-50
determ=determ+dlog(dabs(symtrx(nk)))
c sweeps out the symmetric matrix symtrx for a selected pivot k,
c resulting in the so-called partial inverse useful in stepwise
c regression.
untryd(k)=.false.
c preparation of elimination step
rdumy(k)=1.0/symtrx(nk)
sdumy(k)=1.0
symtrx(nk)=0.0
n=lbefor+k
if (k.eq.1) go to 4
ka=k-1
do 3 j=1,ka
sdumy(j)=symtrx(n)
rdumy(j)=symtrx(n)*rdumy(k)
if (untryd(j)) rdumy(j)=-rdumy(j)
symtrx(n)=0.0
3 n=n+norder-j
4 if (k.eq.norder) go to 6
ka=k+1
do 5 j=ka,norder
n=n+1
sdumy(j)=symtrx(n)
rdumy(j)=-symtrx(n)*rdumy(k)
if (.not.untryd(j)) sdumy(j)=-sdumy(j)
5 symtrx(n)=0.0
c elimination proper
6 n=lbefor
do 7 i=1,norder
do 7 j=i,norder
n=n+1
7 symtrx(n)=symtrx(n)+sdumy(i)*rdumy(j)
return
end
c
c ..................................................................
c
c subroutine eigen
c
c purpose
c compute eigenvalues and eigenvectors of a real symmetric
c matrix
c
c usage
c call eigen(a,r,n,mv)
c
c description of parameters
c a - original matrix (symmetric), destroyed in computation.
c resultant eigenvalues are developed in diagonal of
c matrix a in descending order.
c r - resultant matrix of eigenvectors (stored columnwise,
c in same sequence as eigenvalues)
c n - order of matrices a and r
c mv- input code
c 0 compute eigenvalues and eigenvectors
c 1 compute eigenvalues only (r need not be
c dimensioned but must still appear in calling
c sequence)
c
c remarks
c original matrix a must be real symmetric (storage mode=1)
c matrix a cannot be in the same location as matrix r
c
c subroutines and function subprograms required
c none
c
c method
c diagonalization method originated by jacobi and adapted
c by von neumann for large computers as found in 'mathematical
c methods for digital computers', edited by a. ralston and
c h.s. wilf, john wiley and sons, new york, 1962, chapter 7
c
c ..................................................................
c
subroutine eigen(a,r,n,mv)
dimension a(1),r(1)
c
c ...............................................................
c
c if a double precision version of this routine is desired, the
c c in column 1 should be removed from the double precision
c statement which follows.
c
double precision a,r,anorm,anrmx,thr,x,y,sinx,sinx2,cosx,
1 cosx2,sincs,range
c
c the c must also be removed from double precision statements
c appearing in other routines used in conjunction with this
c routine.
c
c the double precision version of this subroutine must also
c contain double precision fortran functions. sqrt in statements
c 40, 68, 75, and 78 must be changed to dsqrt. abs in statement
c 62 must be changed to dabs. the constant in statement 5 should
c be changed to 1.0d-12.
c
c ...............................................................
c
c generate identity matrix
c
5 range=1.0d-12
if(mv-1) 10,25,10
10 iq=-n
do 20 j=1,n
iq=iq+n
do 20 i=1,n
ij=iq+i
r(ij)=0.0
if(i-j) 20,15,20
15 r(ij)=1.0
20 continue
c
c compute initial and final norms (anorm and anormx)
c
25 anorm=0.0
do 35 i=1,n
do 35 j=i,n
if(i-j) 30,35,30
30 ia=i+(j*j-j)/2
anorm=anorm+a(ia)*a(ia)
35 continue
if(anorm) 165,165,40
40 anorm=1.414d0*dsqrt(anorm)
anrmx=anorm*range/dble(n)
c
c initialize indicators and compute threshold, thr
c
ind=0
thr=anorm
45 thr=thr/dble(n)
50 l=1
55 m=l+1
c
c compute sin and cos
c
60 mq=(m*m-m)/2
lq=(l*l-l)/2
lm=l+mq
62 if(dabs(a(lm))-thr) 130,65,65
65 ind=1
ll=l+lq
mm=m+mq
x=0.5*(a(ll)-a(mm))
68 y=-a(lm)/dsqrt(a(lm)*a(lm)+x*x)
if(x) 70,75,75
70 y=-y
75 sinx=y/dsqrt(2.0*(1.0+(dsqrt(1.0-y*y))))
sinx2=sinx*sinx
78 cosx=dsqrt(1.0-sinx2)
cosx2=cosx*cosx
sincs =sinx*cosx
c
c rotate l and m columns
c
ilq=n*(l-1)
imq=n*(m-1)
do 125 i=1,n
iq=(i*i-i)/2
if(i-l) 80,115,80
80 if(i-m) 85,115,90
85 im=i+mq
go to 95
90 im=m+iq
95 if(i-l) 100,105,105
100 il=i+lq
go to 110
105 il=l+iq
110 x=a(il)*cosx-a(im)*sinx
a(im)=a(il)*sinx+a(im)*cosx
a(il)=x
115 if(mv-1) 120,125,120
120 ilr=ilq+i
imr=imq+i
x=r(ilr)*cosx-r(imr)*sinx
r(imr)=r(ilr)*sinx+r(imr)*cosx
r(ilr)=x
125 continue
x=2.0*a(lm)*sincs
y=a(ll)*cosx2+a(mm)*sinx2-x
x=a(ll)*sinx2+a(mm)*cosx2+x
a(lm)=(a(ll)-a(mm))*sincs+a(lm)*(cosx2-sinx2)
a(ll)=y
a(mm)=x
c
c tests for completion
c
c test for m = last column
c
130 if(m-n) 135,140,135
135 m=m+1
go to 60
c
c test for l = second from last column
c
140 if(l-(n-1)) 145,150,145
145 l=l+1
go to 55
150 if(ind-1) 160,155,160
155 ind=0
go to 50
c
c compare threshold with final norm
c
160 if(thr-anrmx) 165,165,45
c
c sort eigenvalues and eigenvectors
c
165 iq=-n
do 185 i=1,n
iq=iq+n
ll=i+(i*i-i)/2
jq=n*(i-2)
do 185 j=i,n
jq=jq+n
mm=j+(j*j-j)/2
if(a(ll)-a(mm)) 170,185,185
170 x=a(ll)
a(ll)=a(mm)
a(mm)=x
if(mv-1) 175,185,175
175 do 180 k=1,n
ilr=iq+k
imr=jq+k
x=r(ilr)
r(ilr)=r(imr)
180 r(imr)=x
185 continue
return
end
c
c ..................................................................
c
c subroutine nroot
c
c purpose
c compute eigenvalues and eigenvectors of a real nonsymmetric
c matrix of the form b-inverse times a. this subroutine is
c normally called by subroutine canor in performing a
c canonical correlation analysis.
c
c usage
c call nroot (m,a,b,xl,x)
c
c description of parameters
c m - order of square matrices a, b, and x.
c a - input matrix (m x m).
c b - input matrix (m x m).
c xl - output vector of length m containing eigenvalues of
c b-inverse times a.
c x - output matrix (m x m) containing eigenvectors column-
c wise.
c
c remarks
c none
c
c subroutines and function subprograms required
c eigen
c
c method
c refer to w. w. cooley and p. r. lohnes, 'multivariate pro-
c cedures for the behavioral sciences', john wiley and sons,
c 1962, chapter 3.
c
c ..................................................................
c
subroutine nroot (m,a,b,xl,x)
dimension a(1),b(1),xl(1),x(1)
c
c ...............................................................
c
c if a double precision version of this routine is desired, the
c c in column 1 should be removed from the double precision
c statement which follows.
c
double precision a,b,xl,x,sumv
c
c the c must also be removed from double precision statements
c appearing in other routines used in conjunction with this
c routine.
c
c the double precision version of this subroutine must also
c contain double precision fortran functions. sqrt in statements
c 110 and 175 must be changed to dsqrt. abs in statement 110
c must be changed to dabs.
c
c ...............................................................
c
c compute eigenvalues and eigenvectors of b
c
k=1
do 100 j=2,m
l=m*(j-1)
do 100 i=1,j
l=l+1
k=k+1
100 b(k)=b(l)
c
c the matrix b is a real symmetric matrix.
c
mv=0
call eigen (b,x,m,mv)
c
c form reciprocals of square root of eigenvalues. the results
c are premultiplied by the associated eigenvectors.
c
l=0
do 110 j=1,m
l=l+j
110 xl(j)=1.0/dsqrt(dabs(b(l)))
k=0
do 115 j=1,m
do 115 i=1,m
k=k+1
115 b(k)=x(k)*xl(j)
c
c form (b**(-1/2))prime * a * (b**(-1/2))
c
do 120 i=1,m
n2=0
do 120 j=1,m
n1=m*(i-1)
l=m*(j-1)+i
x(l)=0.0
do 120 k=1,m
n1=n1+1
n2=n2+1
120 x(l)=x(l)+b(n1)*a(n2)
l=0
do 130 j=1,m
do 130 i=1,j
n1=i-m
n2=m*(j-1)
l=l+1
a(l)=0.0
do 130 k=1,m
n1=n1+m
n2=n2+1
130 a(l)=a(l)+x(n1)*b(n2)
c
c compute eigenvalues and eigenvectors of a
c
call eigen (a,x,m,mv)
l=0
do 140 i=1,m
l=l+i
140 xl(i)=a(l)
c
c compute the normalized eigenvectors
c
do 150 i=1,m
n2=0
do 150 j=1,m
n1=i-m
l=m*(j-1)+i
a(l)=0.0
do 150 k=1,m
n1=n1+m
n2=n2+1
150 a(l)=a(l)+b(n1)*x(n2)
c
c At this point, the routine differs from the standard ibm nroot.
c The eigenvectors are not normalized to unit length. As a result,
c instead of (x-prime)*(x)=i, we have (x-prime)*b*(x)=i , so that
c the discriminant scores will have unit variances within-groups.
n2 = m*m
do 160 i=1,n2
160 x(i)=a(i)
return
end